//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Workflow.ComponentModel;
using Microsoft.Research.ScientificWorkflow.TridentUtilities;
using Microsoft.Research.ScientificWorkflow;
using Er = Microsoft.Research.DataLayer;
using System.Globalization;
using System.Configuration;

namespace Microsoft.Research.ScientificWorkflow.TridentComposer
{
    /// <summary>
    /// Imports activities.
    /// </summary>
    public class ImportActivity
    {
        #region private Fields
        private Er.Connection registryConn;
        private bool installerInstance;

        private const string MAXALLOWEDVERSIONS = "MaxAllowedVersions";
        private const string AUTODELETEVERSIONS = "AutoDeleteUnusedVersions";
        private const string MANAGEMENTSTUDIOPATH = "ManagementStudioPath";

        #endregion

        #region constructors

        /// <summary>
        /// Initializes a new instance of ImportActivity class.
        /// </summary>
        /// <param name="registryConnection"></param>
        public ImportActivity(Er.Connection registryConnection, bool installerInstance)
        {
            this.registryConn = registryConnection;
            this.installerInstance = installerInstance;
        }

        #endregion

        #region public methods

        /// <summary>
        /// This function is used to update the activity details.
        /// </summary>
        /// <param name="activity">Registry activity.</param>
        /// <param name="actType">Type of the Activity.</param>
        public static void UpdateActivityDetails(
            Er.Activity activity,
            System.Type actType)
        {
            // Get the activity type.
            Er.ActivityType activityType = Er.ActivityType.Leaf;
            if (actType.IsSubclassOf(typeof(CompositeActivity)) ||
                actType.IsInstanceOfType(typeof(CompositeActivity)))
            {
                activityType = Er.ActivityType.Composite;
            }

            try
            {
                activity.Type = activityType;
                activity.ActivityClass = actType.FullName;

                // Set the Fullname of the RegistryActivity.
                activity.FullName = actType.AssemblyQualifiedName;

                // Get the name of the activity from the Custom Attributes.
                object[] attrs = actType.GetCustomAttributes(typeof(NameAttribute), false);
                if (null != attrs && attrs.Length > 0)
                {
                    NameAttribute nameAttr = attrs[0] as NameAttribute;
                    activity.Label = nameAttr.Label;
                    activity.DisplayLabel = nameAttr.DisplayLabel;
                }

                // Get the description of the Activity.
                attrs = actType.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (null != attrs && attrs.Length > 0)
                {
                    DescriptionAttribute descAttr = attrs[0] as DescriptionAttribute;
                    activity.Description = descAttr.Description;
                }

                // Gets the Hidden Attribute
                attrs = actType.GetCustomAttributes(typeof(HideActivityAttribute), false);
                if (null != attrs && attrs.Length > 0)
                {
                    HideActivityAttribute hideAttribute = attrs[0] as HideActivityAttribute;
                    activity.IsHidden = hideAttribute.HideActivity;
                }

                // If the activity is of type IConditionActivity then get the Display label and the set IsCondition to true.
                Type condActivity = actType.GetInterface(typeof(IConditionActivity).FullName);
                if (condActivity != null)
                {
                    activity.IsCondition = true;
                }

                // Save the registry activity.
                activity.Save();
            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                          exp,
                          TridentErrorConstants.ErrorNumber4000067,
                          exp.Message);
            }
        }

        /// <summary>
        /// This function is used to add the activity to the specified category.
        /// If the category is not specified the activity will be added to uncategorized category.
        /// </summary>
        /// <param name="activity">Registry activity.</param>
        /// <param name="actType">Type of the Activity.</param>
        /// <param name="myNamespace">Category of teh activity.</param>
        public static void UpdateActivityCategory(
            Er.Activity activity,
            MemberInfo actType,
            Er.Namespace myNamespace,
            Er.Connection registryConnection,
            bool installerInstance)
        {
            try
            {
                if (myNamespace == null)
                {
                    // Get the category of the activity.
                    string categoryPath = string.Empty;

                    object[] attrs = actType.GetCustomAttributes(typeof(WorkflowCategoryAttribute), false);
                    if (null != attrs && attrs.Length > 0)
                    {
                        WorkflowCategoryAttribute wcAttr = attrs[0] as WorkflowCategoryAttribute;
                        categoryPath = wcAttr.Path;
                    }

                    // Remove the activity from the old category.
                    foreach (Er.Namespace category in activity.Namespaces)
                    {
                        category.Activitys.Remove(activity);
                    }

                    if (!string.IsNullOrEmpty(categoryPath))
                    {
                        // Get the namespace if it is already in the registry.
                        // otherise assign it to uncategorized.
                        myNamespace = CategoriesComposer.GetActivityNamespace(categoryPath, registryConnection, installerInstance);
                    }

                    // If namespace isnt found then save it into uncategorized.
                    if (null == myNamespace)
                    {
                        myNamespace = CategoriesComposer.GetUncategorizedActivityNamespace(registryConnection);
                    }

                    if (null == myNamespace)
                    {
                        TridentErrorHandler.ThrowTridentCustomException(
                            TridentErrorConstants.ErrorNumber4000024,
                            TridentResourceManager.GetString("ActivityCategorySetError"));
                    }
                }

                if (!myNamespace.Activitys.Contains(activity))
                {
                    // Add the activity to the Category.
                    myNamespace.Activitys.Add(activity);
                }

                activity.Namespaces.Refresh();
            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                         exp,
                         TridentErrorConstants.ErrorNumber4000068,
                         exp.Message);
            }
        }


        /// <summary>
        /// This function is used to create the activity parameters in registry.
        /// </summary>
        /// <param name="regActivity">Registry activity.</param>
        /// <param name="actType">Type of the Activity.</param>
        public static void CreateActivityParameters(
            Er.Activity regActivity,
            System.Type actType,
            Er.Connection registryConnection)
        {
            // Create Activity Parameters
            PropertyInfo[] propertyInfo = actType.GetProperties();
            if (propertyInfo != null)
            {
                foreach (PropertyInfo prop in propertyInfo)
                {
                    object[] inAtts = prop.GetCustomAttributes(typeof(InputParamAttribute), false);
                    if (inAtts.Length > 0)
                    {
                        CreateInputParameter(regActivity, actType, prop, (inAtts[0] as InputParamAttribute).IsRequired, registryConnection);
                    }

                    object[] outAtts = prop.GetCustomAttributes(typeof(OutputParamAttribute), false);
                    if (outAtts.Length > 0)
                    {
                        CreateOutputParameter(regActivity, prop, registryConnection);
                    }

                    object[] inOutAtts = prop.GetCustomAttributes(typeof(InOutParamAttribute), false);
                    if (inOutAtts.Length > 0)
                    {
                        CreateInputParameter(regActivity, actType, prop, (inOutAtts[0] as InOutParamAttribute).IsRequired, registryConnection);
                        CreateOutputParameter(regActivity, prop, registryConnection);
                    }
                }

                regActivity.ActivityParameters.Refresh();
            }
        }

        /// <summary>
        /// Import the activities from the file references.
        /// </summary>
        /// <param name="fileReferences">The file references.</param>
        /// <param name="updatedActivities">The list to which the new created activities need to be cached in. Null if not needed.</param>
        /// <returns>
        /// True = If import succeeds.
        /// False = if user selects to not to import the activities.
        /// </returns>
        public bool ImportActivities(Collection<FileReference> fileReferences, Dictionary<string, Er.Activity> updatedActivities, bool createNewVersionOnNameMatch)
        {
            bool importSucceeded = true;
            if (fileReferences != null)
            {
                // The activities to update. If any of the non activity images are selected to update then collect the activities referred in a list.
                Dictionary<Guid, ActivityUpdateDetails> activitiesToUpdate = new Dictionary<Guid, ActivityUpdateDetails>();

                // Get the file associations.
                IEnumerable<FileReference> activities = fileReferences.Where(file => file.ContainsActivity);
                Collection<FileReference> traversedActivities = new Collection<FileReference>();
                foreach (FileReference activityFile in activities)
                {
                    // If any activity file has the same checksum of an activity already imported then continue to the next file.
                    if (!string.IsNullOrEmpty(activityFile.Checksum) && traversedActivities.Any(a => a.Checksum.Equals(activityFile.Checksum, StringComparison.Ordinal)))
                    {
                        continue;
                    }
                    traversedActivities.Add(activityFile);

                    Collection<FileReference> activityAssociations = new Collection<FileReference>();
                    FileReference.GetAllAssociatedFiles(activityFile, fileReferences, activityAssociations);

                    if (!string.IsNullOrEmpty(activityFile.Checksum))
                    {
                        // If the activity file itself is one of the references then remove the file.
                        FileReference duplicateActivityFile =
                            activityAssociations.FirstOrDefault(a => (a.Checksum != null && a.Checksum.Equals(activityFile.Checksum, StringComparison.OrdinalIgnoreCase)));
                        if (duplicateActivityFile != null)
                        {
                            activityAssociations.Remove(duplicateActivityFile);
                        }
                    }

                    // Check if all the required files are already in the registry. If so dont import.
                    // This check is needed only for workflow import path as for activity import this check is already made.
                    Er.AssemblyPackage requiredPackage = null;
                    if (!CheckIfImportRequired(activityFile, activityAssociations, this.registryConn, ref requiredPackage))
                    {
                        GetActivitiesFromPackage(requiredPackage, updatedActivities);
                        continue;
                    }

                    // If the control has come till here, it means that some files have been modified/added.
                    // If the activity file's copy is present in registry. Then create newer versions of the activities. Set update existing to true.
                    if (activityFile.CopyExistsInRegistry != null && activityFile.CopyExistsInRegistry.Value)
                    {
                        activityFile.UpdateExisting = true;
                        activityFile.AssemblyInRegistryToUpdate = new AssemblyMetadata() { Id = activityFile.AssemblyImageIdOfCopy };
                    }

                    // Import activities.
                    Assembly activityAssembly = AssemblyLoad.LoadFrom(activityFile.FilePath);

                    try
                    {
                        // Create assembly package.
                        Er.AssemblyPackage asmPkg = this.CreateAssemblyPackage(activityFile.FilePath, fileReferences, activityAssociations, activitiesToUpdate);

                        if (asmPkg != null)
                        {
                            // Iterate through the assembly for activities.
                            foreach (Type actType in activityAssembly.GetTypes())
                            {
                                // Search only the activity types.
                                if (actType.IsSubclassOf(typeof(Activity)))
                                {
                                    Er.Activity newActivity = null;

                                    // If the user has opted to update and existing assembly then create newer versions of the activities in the 
                                    //  assembly selected. Else create new actiivties.
                                    if (!activityFile.UpdateExisting)
                                    {
                                        // Check if the activity with the same name already exists in registry.
                                        Er.Activity regActivity = Er.Activity.CommonSearches.FindActivityInRegistry(actType.FullName, this.registryConn);

                                        // If activity is in registry then update else create new,
                                        if (regActivity != null)
                                        {
                                            if (createNewVersionOnNameMatch)
                                            {
                                                newActivity = this.CreateNewVersion(actType, regActivity, asmPkg);

                                                Guid oldVersionId = (regActivity as Er.IObject).ID;

                                                // If the old activity has been marked for update already remove it from the dictionary as
                                                // the newer version will have the new Image anyway. 
                                                if (activitiesToUpdate.ContainsKey(oldVersionId))
                                                {
                                                    activitiesToUpdate.Remove(oldVersionId);
                                                }
                                            }
                                            else
                                            {
                                                // Update the name/label with the timestamp to maintain uniqueness.
                                                newActivity = this.CreateActivity(actType, null, asmPkg);
                                                ImportActivity.AddTimestampToLabel(newActivity);
                                            }
                                        }
                                        else
                                        {
                                            newActivity = this.CreateActivity(actType, null, asmPkg);
                                        }
                                    }
                                    else
                                    {
                                        // If any new activities have been added to the assembly then create new activity in registry for each.
                                        // Else create a newer version.
                                        Er.AssemblyImage selectedImage =
                                            Er.AssemblyImage.Load(activityFile.AssemblyInRegistryToUpdate.Id, this.registryConn);
                                        Er.Activity oldVersion = ImportActivity.GetActivityFromImage(actType, selectedImage);
                                        if (oldVersion == null)
                                        {
                                            // Check if the activity with the same name already exists in registry.
                                            Er.Activity regActivity = Er.Activity.CommonSearches.FindActivityInRegistry(actType.FullName, this.registryConn);
                                            newActivity = this.CreateActivity(actType, null, asmPkg);

                                            // If the activity with the same name already exists in registry then append the datetimestamp to the label.
                                            if (regActivity != null)
                                            {
                                                ImportActivity.AddTimestampToLabel(newActivity);
                                            }
                                        }
                                        else
                                        {
                                            newActivity = this.CreateNewVersion(actType, oldVersion, asmPkg);

                                            Guid oldVersionId = (oldVersion as Er.IObject).ID;

                                            // If the old activity has been marked for update already remove it from the dictionary as
                                            // the newer version will have the new Image anyway. 
                                            if (activitiesToUpdate.ContainsKey(oldVersionId))
                                            {
                                                activitiesToUpdate.Remove(oldVersionId);
                                            }
                                        }
                                    }

                                    if (updatedActivities != null)
                                    {
                                        // Add to the updated activity list. Needed while creating a workflow out of the activities.
                                        updatedActivities[actType.FullName] = newActivity;
                                    }
                                }
                            }


                        }
                        else
                        {
                            // Assembly package can only be null if there is no activity present in the 
                            // DLL which is being imported. So, throw no activities present exception.
                            TridentErrorHandler.ThrowTridentCustomException(
                                TridentErrorConstants.ErrorNumber4000071,
                                TridentResourceManager.GetString("ErrorNoActivitiesFoundInAssembly"));
                            importSucceeded = false;
                        }
                    }
                    catch (BadImageFormatException ex)
                    {
                        importSucceeded = false;
                        TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000024, ex.Message);
                    }
                    catch (FileLoadException ex)
                    {
                        importSucceeded = false;
                        TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000024, ex.Message);
                    }
                    catch (TargetInvocationException)
                    {
                        importSucceeded = false;
                        TridentErrorHandler.ThrowTridentCustomException(
                            TridentErrorConstants.ErrorNumber4000026,
                            TridentResourceManager.GetString("ImportOfActivityFailed"));
                    }
                }
                this.CreateActivitiesVersionsWithNewImages(activitiesToUpdate);
            }

            return importSucceeded;
        }
        #endregion

        #region private methods
        /// <summary>
        /// Create assembly package from the references passed.
        /// </summary>
        /// <param name="assemblyLoadPath">The path of the assembly.</param>
        /// <param name="references">The file references.</param>
        /// <param name="containsActivity">True if the references contain activity.False otherwise.</param>
        /// <returns>The Assembly package created.</returns>
        private Er.AssemblyPackage CreateAssemblyPackage(string assemblyLoadPath,
            Collection<FileReference> references,
            Collection<FileReference> associatedFiles,
            Dictionary<Guid, ActivityUpdateDetails> activitiesToUpdate)
        {
            Er.AssemblyPackage newAssemblyPackage = null;

            try
            {
                FileReference assemblyFileRef =
                    references.FirstOrDefault(f => f.FilePath.Equals(assemblyLoadPath, StringComparison.OrdinalIgnoreCase));
                if (assemblyFileRef != null)
                {
                    Er.AssemblyImage activityDllImage = null;

                    // Get the filename for the assembly package.
                    string fileName = Path.GetFileNameWithoutExtension(assemblyFileRef.FilePath);

                    Collection<Er.AssemblyPackage> oldPackages = Er.AssemblyPackage.CommonSearches.GetAssemblyPackage(this.registryConn, fileName);

                    // Create the assembly package.
                    newAssemblyPackage = Er.AssemblyPackage.Create(fileName, this.registryConn);

                    if (oldPackages != null && oldPackages.Count != 0)
                    {
                        newAssemblyPackage.Label = string.Format(CultureInfo.InvariantCulture, "{0} {1}", fileName, DateTime.Now.ToString(CultureInfo.CurrentCulture));
                    }
                    newAssemblyPackage.Save();

                    // Get the Assembly image related to the Assembly.
                    activityDllImage = this.GetAssemblyImage(assemblyFileRef, activitiesToUpdate);
                    activityDllImage.IsActivityDll = true;
                    activityDllImage.Save();

                    RemoveHiddenPackages(activityDllImage, oldPackages);

                    newAssemblyPackage.AssemblyImages.Add(activityDllImage);

                    // Create an assembly image for each reference and add it to the package.
                    foreach (FileReference associatedFile in associatedFiles)
                    {
                        // If update existing is selected then create a new version of the selected assembly. 
                        // Else create a new assembly image.
                        Er.AssemblyImage dependencyImage = this.GetAssemblyImage(associatedFile, activitiesToUpdate);

                        // Add the reference of the Assembly Image to the Assembly package.
                        newAssemblyPackage.AssemblyImages.Add(dependencyImage);

                    }
                }
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber4000081,
                    TridentResourceManager.GetString("PackageCreateError"));
            }
            return newAssemblyPackage;
        }

        /// <summary>
        /// Removes the hidden packages, workflow and activities.
        /// </summary>
        /// <param name="activityDllImage">The activity DLL image.</param>
        /// <param name="oldPackages">The old packages.</param>
        private static void RemoveHiddenPackages(Er.AssemblyImage activityDllImage, Collection<Er.AssemblyPackage> oldPackages)
        {
            bool isAutoDeleteEnabled = true;
            if (ConfigurationManager.AppSettings.AllKeys.Contains(AUTODELETEVERSIONS))
            {
                if (!bool.TryParse(ConfigurationManager.AppSettings[AUTODELETEVERSIONS], out isAutoDeleteEnabled))
                {
                    isAutoDeleteEnabled = true;
                }
            }

            if (isAutoDeleteEnabled)
            {
                int maxAllowedVersions = 15;
                if (ConfigurationManager.AppSettings.AllKeys.Contains(MAXALLOWEDVERSIONS))
                {
                    if (!int.TryParse(ConfigurationManager.AppSettings[MAXALLOWEDVERSIONS], out maxAllowedVersions))
                    {
                        maxAllowedVersions = 15;
                    }
                }

                // Before importing need to check if the activities version count, workflow version count ismore than specified:
                // If yes then automatically delete the hidden workflow and respected activities and assemblies.
                List<Er.AssemblyImage> previousVersions = Er.AssemblyImage.GetPreviousVersions(activityDllImage);

                int totalVersionToDelete = previousVersions.Count - maxAllowedVersions;
                if (totalVersionToDelete > 0)
                {
                    int deletedVersions = 0;

                    for (int index = 0; (index < previousVersions.Count - 1 && deletedVersions < totalVersionToDelete); index++)
                    {
                        Er.AssemblyImage oldestVersion = previousVersions[index];

                        // Refresh is to make sure that the latest details is updated in AssemblyImage.
                        oldestVersion.Refresh();

                        Er.AssemblyPackage deletePackage = oldPackages
                            .FirstOrDefault(oldPackage => oldPackage.AssemblyImages.Contains(oldestVersion, new Er.AssemblyImageComparer()));

                        if (deletePackage != null)
                        {
                            bool canDeleteAssembly = true;
                            foreach (Er.Activity activity in deletePackage.Activitys)
                            {
                                bool canDelete = true;
                                Er.Activity.FetchAllWorkflows(activity)
                                    .ForEach(workflow =>
                                        {
                                            if (!workflow.IsLatestVersion()
                                                && string.IsNullOrEmpty(workflow.VersionLabel)
                                                && (!workflow.HasAssocitedJobs()))
                                            {
                                                workflow.DeleteUnusedWorkflow();
                                            }
                                            else
                                            {
                                                canDelete = false;
                                            }
                                        });

                                if (!canDelete)
                                {
                                    canDeleteAssembly = false;
                                }
                            }

                            if (canDeleteAssembly)
                            {
                                foreach (Er.Activity activity in deletePackage.Activitys)
                                {
                                    activity.DeleteUnused();
                                }

                                oldestVersion.DeleteUnused();

                                deletePackage.AssemblyImages.Clear();
                                deletePackage.Delete();

                                deletedVersions++;
                            }
                        }
                    }

                    if (deletedVersions < totalVersionToDelete)
                    {
                        // But still the count is more, then show message to user saying delete.
                        System.Windows.MessageBox.Show(
                            string.Format(CultureInfo.InvariantCulture, TridentCommonResourceManager.GetString("VersionsFeedbackMessage"), maxAllowedVersions),
                            "Scientific WorkFlow",
                             System.Windows.MessageBoxButton.OK,
                              System.Windows.MessageBoxImage.Warning);
                    }
                }
            }
        }

        /// <summary>
        /// Get the required assembly image.
        /// </summary>
        /// <param name="reference">The file reference.</param>
        private Er.AssemblyImage GetAssemblyImage(FileReference reference, Dictionary<Guid, ActivityUpdateDetails> activitiesToUpdate)
        {
            Er.AssemblyImage newImage = null;

            try
            {
                // If a copy already exists in the registry then use the same image.
                if (reference.CopyExistsInRegistry != null && reference.CopyExistsInRegistry.Value)
                {
                    newImage = Er.AssemblyImage.Load(reference.AssemblyImageIdOfCopy, this.registryConn);
                }
                else
                {
                    // If create new is chosen, create an assembly image.
                    if (!reference.UpdateExisting)
                    {
                        newImage = this.CreateAssemblyImage(reference.FilePath);
                    }
                    else
                    {
                        // Create a new version of the existing image.
                        Er.AssemblyImage imageToUpdate =
                            Er.AssemblyImage.Load(reference.AssemblyInRegistryToUpdate.Id, this.registryConn);
                        newImage = this.CreateAssemblyImageVersion(imageToUpdate, reference.FilePath);

                        if (!reference.ContainsActivity)
                        {
                            this.GetActivitiesToUpdate(reference, activitiesToUpdate, newImage);
                        }
                    }
                }
            }
            catch (Er.RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                   TridentErrorConstants.ErrorNumber4000082,
                   TridentResourceManager.GetString("AssemblyImageNotFound"));
            }
            return newImage;
        }

        /// <summary>
        /// Create a new assembly image.
        /// </summary>
        /// <param name="filePath">The file for which the assembly image is to be created.</param>
        /// <returns>The new assembly image.</returns>
        private Er.AssemblyImage CreateAssemblyImage(string filePath)
        {
            Er.AssemblyImage asmImg = null;
            FileInfo fileInfo = new FileInfo(filePath);

            if (fileInfo != null)
            {
                try
                {
                    // Determine the type of the file.
                    Er.AssemblyType type = Er.AssemblyType.Unknown;
                    if (Helper.IsAssemblyFile(fileInfo.FullName))
                    {
                        if (Helper.IsManagedAssembly(fileInfo.FullName))
                        {
                            type = Er.AssemblyType.DotNET;
                        }
                        else
                        {
                            type = Er.AssemblyType.WindowsDLL;
                        }
                    }
                    else
                    {
                        type = Er.AssemblyType.DataFile;
                    }

                    string newImageName;

                    // If an image already exists by the same name, add a timestamp to the image name.
                    Collection<Er.AssemblyImage> image = Er.AssemblyImage.CommonSearches.GetAssemblyImagesByName(fileInfo.Name, this.registryConn);
                    if (image == null)
                    {
                        newImageName = fileInfo.Name;
                    }
                    else
                    {
                        newImageName = string.Format(CultureInfo.InvariantCulture, "{0} - {1}", fileInfo.Name, DateTime.Now.ToString(CultureInfo.CurrentCulture));
                    }

                    // Create the Assmbly Image.
                    asmImg = Er.AssemblyImage.Create(newImageName, type, this.registryConn);
                    asmImg.ContentsSize = (int)fileInfo.Length;
                    asmImg.FileCreateDate = fileInfo.CreationTime;
                    asmImg.FileModifyDate = fileInfo.LastWriteTime;
                    asmImg.Filename = fileInfo.Name;
                    asmImg.FileExtension = fileInfo.Extension;

                    // Get the contents of the file to create a checksum. This byte array will also be used to create the image in registry.
                    byte[] fileContent = Helper.ReadBytesFromAssemblyFile(fileInfo.FullName);
                    asmImg.Checksum = Helper.CreateChecksum(fileContent);

                    // Save the changes to registry.
                    asmImg.Save();

                    // Update the assembly Contents.
                    this.UpdateAssemblyImageContents(asmImg, fileContent);
                }
                catch (Exception exp)
                {
                    TridentErrorHandler.HandleAndThrowBusinessLogicException(
                            exp,
                            TridentErrorConstants.ErrorNumber6000017,
                            exp.Message);
                }

            }
            return asmImg;
        }

        /// <summary>
        /// Create a new version of the image specified.
        /// </summary>
        /// <param name="assemblyImage">The assembly image.</param>
        /// <param name="filePath">The path of the new file.</param>
        /// <returns>The new version of the assembly image.</returns>
        private Er.AssemblyImage CreateAssemblyImageVersion(Er.AssemblyImage assemblyImage, string filePath)
        {
            #region argument validation
            if (assemblyImage == null)
            {
                throw new ArgumentNullException("assemblyImage");
            }
            if (string.IsNullOrEmpty(filePath))
            {
                throw new ArgumentNullException("filePath");
            }
            #endregion
            Er.AssemblyImage newVersion = null;
            FileInfo fileInfo = new FileInfo(filePath);

            try
            {
                newVersion = assemblyImage.CreateNewVersion(this.registryConn);

                // If an image already exists by the same name, add a timestamp to the image name.
                Collection<Er.AssemblyImage> image = Er.AssemblyImage.CommonSearches.GetAssemblyImagesByName(fileInfo.Name, this.registryConn);
                if (image == null)
                {
                    newVersion.Name = fileInfo.Name;
                }
                else
                {
                    newVersion.Name = string.Format(CultureInfo.InvariantCulture, "{0} - {1}", fileInfo.Name, DateTime.Now.ToString(CultureInfo.CurrentCulture));
                }

                // Set the file details.
                newVersion.ContentsSize = (int)fileInfo.Length;
                newVersion.FileCreateDate = fileInfo.CreationTime;
                newVersion.FileModifyDate = fileInfo.LastWriteTime;
                newVersion.Filename = fileInfo.Name;

                // Get the contents of the file to create a checksum. This byte array will also be used to create the image in registry.
                byte[] fileContent = Helper.ReadBytesFromAssemblyFile(fileInfo.FullName);
                newVersion.Checksum = Helper.CreateChecksum(fileContent);

                // Save the changes to registry.
                newVersion.Save();

                // Add the new version to the newversion collection of the old image.
                Er.AssemblyImageVersion versionBinding =
                    Er.AssemblyImageVersion.Create(assemblyImage,
                    newVersion,
                    Er.VersionRelationshipType.Concrete,
                    this.registryConn);
                assemblyImage.NewerVersions.Add(versionBinding);

                // Update the assembly Contents.
                this.UpdateAssemblyImageContents(newVersion, fileContent);
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                        exp,
                        TridentErrorConstants.ErrorNumber4000080,
                        exp.Message);
            }
            return newVersion;
        }

        /// <summary>
        /// This function is used to update the Assembly image contents 
        /// in registry from the assembly file.
        /// </summary>
        /// <param name="asmImg">Assembly image which has to be updated.</param>
        /// <param name="assemblyFile">Assembly file.</param>
        /// <returns>AssemblyImage.</returns>
        private void UpdateAssemblyImageContents(Er.AssemblyImage asmImg, byte[] fileContent)
        {
            // Workaround for saving the contents of the Assembly into Registry.
            // Remove thos once the autosave is implemented in Registry.
            this.registryConn.AutoSave = true;

            try
            {
                asmImg.Contents = fileContent;
                asmImg.Refresh();
            }
            finally
            {
                if (!this.installerInstance)
                {
                    this.registryConn.AutoSave = false;
                }
            }
        }

        /// <summary>
        /// Retrieve a activity which refers the required image and has a similar name.
        /// </summary>
        /// <param name="activityType">The activity type.</param>
        /// <param name="image">The assembly image to search.</param>
        /// <returns>The activity object.</returns>
        private static Er.Activity GetActivityFromImage(System.Type activityType, Er.AssemblyImage image)
        {
            Er.Activity latestActivity = null;
            Collection<Er.Activity> relatedActivities = null;
            foreach (Er.AssemblyPackage package in image.AssemblyPackages)
            {
                relatedActivities =
                    package.GetActivity(activityType.FullName);
                if (relatedActivities != null)
                {
                    latestActivity = relatedActivities.FirstOrDefault(a => a.IsLatestVersion());
                    if (latestActivity != null)
                    {
                        break;
                    }
                }
            }

            return latestActivity;
        }


        /// <summary>
        /// This is used to Create activity in the registry.
        /// </summary>
        /// <param name="actType">Type of the Activity.</param>
        /// <returns>Activity Created in Registry.</returns>
        private Er.Activity CreateActivity(Type actType, Er.Namespace actCategory, Er.AssemblyPackage package)
        {
            #region Validation of Arguments

            if (null == actType)
            {
                throw new ArgumentNullException("actType");
            }
            if (null == package)
            {
                throw new ArgumentNullException("package");
            }

            #endregion

            // Create activity in registry.
            Er.Activity regActivity = GetActivity(actType);

            // Update the activity details.
            UpdateActivityDetails(regActivity, actType);

            // Update the category.
            UpdateActivityCategory(regActivity, actType, actCategory, this.registryConn, this.installerInstance);

            // Create activity parameters.
            CreateActivityParameters(regActivity, actType, this.registryConn);

            if (package == null)
            {
                // Create assembly package.
                //this.CreateAssemblyPackage(regActivity, actType, references, true);
            }
            else
            {
                // Add the package
                regActivity.AssemblyPackages.Add(package);
            }

            regActivity.Refresh();

            return regActivity;
        }

        /// <summary>
        /// This function is used to create the activity in registry if not present.
        /// </summary>
        /// <param name="actType">Type of the Activity.</param>
        /// <returns></returns>
        private Er.Activity GetActivity(
            System.Type actType)
        {
            Er.Activity regActivity = null;
            string activityName = actType.Name;

            // Get the activity type.
            Er.ActivityType activityType = Er.ActivityType.Leaf;
            if (actType.IsSubclassOf(typeof(CompositeActivity)) ||
                actType.IsInstanceOfType(typeof(CompositeActivity)))
            {
                activityType = Er.ActivityType.Composite;
            }

            try
            {
                // Create Activity in registry.
                regActivity = Er.Activity.Create(activityName, activityType, TridentAuthentication.LoggedInUser, this.registryConn);

                // Save the registry activity.
                regActivity.Save();

            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                          exp,
                          TridentErrorConstants.ErrorNumber6000014,
                          TridentResourceManager.GetString("ActivityCreateError"));
            }

            return regActivity;
        }

        /// <summary>
        /// Create new version of an activity.
        /// </summary>
        /// <param name="activityType">The type of the activity.</param>
        /// <param name="activity">The activity for which a new version is to be created.</param>
        /// <param name="package">The assembly package.</param>
        /// <returns>The new version of the activity.</returns>
        private Er.Activity CreateNewVersion(Type activityType, Er.Activity activity, Er.AssemblyPackage package)
        {
            if (!activity.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser))
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000085,
                    TridentCommonResourceManager.GetString("WorkflowPermissionDenied"));
            }

            Er.Activity newVersion = activity.CreateNewVersion(this.registryConn);
            newVersion.Save();

            //Inherit the ACL Info
            Er.Activity.InheritACLInfo(activity, newVersion, this.registryConn);

            // Create version bindings.
            Er.ActivityVersion activityVersion =
                Er.ActivityVersion.Create(activity, newVersion, Er.VersionRelationshipType.Concrete, this.registryConn);
            activity.NewerVersions.Add(activityVersion);

            // Update the activity details.
            UpdateActivityDetails(newVersion, activityType);

            // Update the category.
            UpdateActivityCategory(newVersion, activityType, null, this.registryConn, this.installerInstance);

            // Create activity parameters.
            CreateActivityParameters(newVersion, activityType, this.registryConn);

            // Add the package
            newVersion.AssemblyPackages.Add(package);

            newVersion.Refresh();

            return newVersion;
        }

        /// <summary>
        /// Create new version of the activity from the activity.
        /// </summary>
        /// <param name="activity">The activity for which a newer version needs to be created.</param>
        /// <param name="package">The package for the new version.</param>
        /// <returns>The newer version of the activity.</returns>
        private Er.Activity CreateNewVersion(Er.Activity activity, Er.AssemblyPackage package)
        {
            if (!activity.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser))
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000085,
                    TridentCommonResourceManager.GetString("WorkflowPermissionDenied"));
            }

            Er.Activity newVersion = activity.CreateNewVersion(this.registryConn);
            newVersion.Save();

            //Inherit the ACL Info
            Er.Activity.InheritACLInfo(activity, newVersion, this.registryConn);
            
            // Create version bindings.
            Er.ActivityVersion activityVersion =
                Er.ActivityVersion.Create(activity, newVersion, Er.VersionRelationshipType.Concrete, this.registryConn);
            activity.NewerVersions.Add(activityVersion);
            activity.Namespaces[0].Activitys.Add(newVersion);

            foreach (Er.ActivityParameter parameter in activity.ActivityParameters)
            {
                Er.ActivityParameter.CopyHelper copyHelper = new Er.ActivityParameter.CopyHelper(newVersion);
                copyHelper.CopyTo(this.registryConn, parameter);
            }

            // Add the package
            newVersion.AssemblyPackages.Add(package);
            return newVersion;
        }

        /// <summary>
        /// Saves Input parameters for the Activity in the Registry.
        /// </summary>
        /// <param name="regActivity">Activity for which the Input parameters has to be saved.</param>
        /// <param name="actType">Activity Type.</param>
        /// <param name="param">ParameterInfo of the Parameter.</param>
        /// <returns>ActivityParameter instance.</returns>
        private static Er.ActivityParameter CreateInputParameter(
            Er.Activity regActivity,
            System.Type type,
            PropertyInfo param,
            bool isMandatory,
            Er.Connection registryConnection)
        {
            Er.ActivityParameter regParam = null;
            try
            {
                regParam = Er.ActivityParameter.Create(param.Name,
                    param.PropertyType.FullName,
                    Er.DirectionType.Input,
                    regActivity,
                    registryConnection);

                regParam.ParameterClass = param.Name;
                regParam.Required = isMandatory;

                object[] attrs = param.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attrs.Length > 0)
                {
                    DescriptionAttribute descAttr = attrs[0] as DescriptionAttribute;
                    regParam.Description = descAttr.Description;
                }

                attrs = param.GetCustomAttributes(typeof(NameAttribute), false);
                if (attrs.Length > 0)
                {
                    NameAttribute nameAttr = attrs[0] as NameAttribute;
                    regParam.Label = nameAttr.Label;
                }

                DependencyProperty depProp = ActivityComposer.GetDependencyProperty(type, param.Name + "Property");
                if (depProp != null)
                {
                    object defaultValue = null;
                    if (depProp.DefaultMetadata != null && depProp.DefaultMetadata.DefaultValue != null)
                    {
                        defaultValue = depProp.DefaultMetadata.DefaultValue;
                        regParam.DefaultValue = defaultValue.ToString();
                    }
                }

                // Save the changes to the registry.
                regParam.Save();
            }
            catch (FileNotFoundException exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                          exp,
                          TridentErrorConstants.ErrorNumber6000015,
                          TridentResourceManager.GetString("FileDependencyError"));
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                          exp,
                          TridentErrorConstants.ErrorNumber6000015,
                          exp.Message);
            }

            regParam.Refresh();
            return regParam;
        }

        /// <summary>
        /// Saves Output parameters for the Activity in the Registry.
        /// </summary>
        /// <param name="regActivity">Activity for which the Output parameters has to be saved.</param>
        /// <param name="actType">Activity Type.</param>
        /// <param name="param">ParameterInfo of the Parameter.</param>
        /// <returns>ActivityParameter instance.</returns>
        private static Er.ActivityParameter CreateOutputParameter(
            Er.Activity regActivity,
            PropertyInfo param,
            Er.Connection registryConnection)
        {
            Er.ActivityParameter regParam = null;
            object[] attrs;
            try
            {
                regParam = Er.ActivityParameter.Create(param.Name,
                    param.PropertyType.FullName,
                    Er.DirectionType.Output,
                    regActivity,
                    registryConnection);

                regParam.ParameterClass = param.Name;

                attrs = param.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attrs.Length > 0)
                {
                    DescriptionAttribute descAttr = attrs[0] as DescriptionAttribute;
                    regParam.Description = descAttr.Description;
                }

                attrs = param.GetCustomAttributes(typeof(NameAttribute), false);
                if (attrs.Length > 0)
                {
                    NameAttribute nameAttr = attrs[0] as NameAttribute;
                    regParam.Label = nameAttr.Label;
                }

                // Save the changes to the registry.
                regParam.Save();
            }
            catch (FileNotFoundException exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                          exp,
                          TridentErrorConstants.ErrorNumber6000015,
                          TridentResourceManager.GetString("FileDependencyError"));
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                          exp,
                          TridentErrorConstants.ErrorNumber6000016,
                          exp.Message);
            }

            regParam.Refresh();
            return regParam;
        }

        /// <summary>
        /// Get activities from package.
        /// </summary>
        /// <param name="packageToQuery">The package</param>
        /// <param name="updatedActivities">The dictionary of activities.</param>
        private static void GetActivitiesFromPackage(Er.AssemblyPackage packageToQuery, Dictionary<string, Er.Activity> updatedActivities)
        {
            foreach (Er.Activity referredActivity in packageToQuery.Activitys)
            {
                if (!referredActivity.IsWorkflow)
                {
                    updatedActivities[referredActivity.ActivityClass] = referredActivity;
                }
            }
        }

        /// <summary>
        /// Check if an import is needed for the Dlls selected. 
        /// If a package exists with all the files the user has selected then an import is not necessary.
        /// Return an assembly package which contains all files.
        /// </summary>
        /// <param name="assemblyFile">The activity file.</param>
        /// <param name="fileAssociations">The file associations of the activity.</param>
        /// <param name="registryConnection">The registry connection</param>
        /// <param name="requiredPackage">The package containing all files.</param>
        /// <returns>True if an import is necessary. False otherwise.</returns>
        public static bool CheckIfImportRequired(FileReference assemblyFile,
            Collection<FileReference> fileAssociations,
            Er.Connection registryConnection,
            ref Er.AssemblyPackage requiredPackage)
        {
            bool importRequired = false;

            // First level of check- If the activity dll itself is not present in registry then import is necessary.
            if (!assemblyFile.CopyExistsInRegistry.HasValue || !assemblyFile.CopyExistsInRegistry.Value)
            {
                importRequired = true;
            }
            else
            {
                // Get the packages using the image.
                Er.AssemblyImage registryCopy = Er.AssemblyImage.Load(assemblyFile.AssemblyImageIdOfCopy, registryConnection);

                // Find a package which contains all the associated files. If found then it means that no import is necessary.
                foreach (Er.AssemblyPackage referredPackage in registryCopy.AssemblyPackages)
                {
                    // Second level of check - File count check. Adding 1 because the fileassociations doesnt contain the activity dll.
                    referredPackage.AssemblyImages.GetEnumerator();
                    if (referredPackage.AssemblyImages.Count != fileAssociations.Count + 1)
                    {
                        continue;
                    }

                    bool allFilesPresentInPackage = true;

                    // Check if all assocaitions are present in the package.
                    foreach (FileReference association in fileAssociations)
                    {
                        bool imagePresentInPackage = referredPackage.AssemblyImages.Any(
                            p => ((p as Er.IObject).ID.Equals(association.AssemblyImageIdOfCopy)
                                || p.Checksum.Equals(association.Checksum)));
                        if (!imagePresentInPackage)
                        {
                            allFilesPresentInPackage = false;
                            break;
                        }
                    }
                    if (allFilesPresentInPackage)
                    {
                        requiredPackage = referredPackage;
                        break;
                    }
                }
                if (requiredPackage == null)
                {
                    importRequired = true;
                }
            }
            return importRequired;
        }

        /// <summary>
        /// Check if an import is needed for the Dlls selected. 
        /// If a package exists with all the files the user has selected then an import is not necessary.
        /// </summary>
        /// <param name="assemblyFile">The activity file.</param>
        /// <param name="fileAssociations">The file associations of the activity.</param>
        /// <param name="registryConnection">The registry connection</param>
        /// <returns>True if an import is necessary. False otherwise.</returns>
        public static bool CheckIfImportRequired(FileReference assemblyFile,
            Collection<FileReference> fileAssociations,
            Er.Connection registryConnection)
        {
            bool importRequired = false;

            // First level of check- If the activity dll itself is not present in registry then import is necessary.
            if (!assemblyFile.CopyExistsInRegistry.HasValue || !assemblyFile.CopyExistsInRegistry.Value)
            {
                importRequired = true;
            }
            else
            {
                // Second level of check. If any file is new then import required.
                if (fileAssociations.Any(a => (!a.CopyExistsInRegistry.Value)))
                {
                    importRequired = true;
                }
                else
                {
                    // Get the packages using the image.
                    Er.AssemblyImage registryCopy = Er.AssemblyImage.Load(assemblyFile.AssemblyImageIdOfCopy, registryConnection);
                    Er.AssemblyPackage requiredPackage = null;

                    // Find a package which contains all the associated files. If found then it means that no import is necessary.
                    foreach (Er.AssemblyPackage referredPackage in registryCopy.AssemblyPackages)
                    {
                        // Third level of check - File count check. Adding 1 because the fileassociations doesnt contain the activity dll.
                        referredPackage.AssemblyImages.GetEnumerator();
                        if (referredPackage.AssemblyImages.Count != fileAssociations.Count + 1)
                        {
                            continue;
                        }

                        bool allFilesPresentInPackage = true;

                        // Check if all assocaitions are present in the package.
                        foreach (FileReference association in fileAssociations)
                        {
                            bool imagePresentInPackage = referredPackage.AssemblyImages.Any(
                            p => ((p as Er.IObject).ID.Equals(association.AssemblyImageIdOfCopy)
                                || p.Checksum.Equals(association.Checksum)));
                            if (!imagePresentInPackage)
                            {
                                allFilesPresentInPackage = false;
                                break;
                            }
                        }
                        if (allFilesPresentInPackage)
                        {
                            requiredPackage = referredPackage;
                            break;
                        }
                    }
                    if (requiredPackage == null)
                    {
                        importRequired = true;
                    }
                }
            }
            return importRequired;
        }

        /// <summary>
        /// Get the activities referring the image for which newer version needs to be created.
        /// </summary>
        /// <param name="fileReference">The file reference of the image.</param>
        /// <param name="activitiesToUpdate">The activities to update</param>
        /// <param name="newImage">The new images to use for the newer versions.</param>
        private void GetActivitiesToUpdate(FileReference fileReference,
            Dictionary<Guid, ActivityUpdateDetails> activitiesToUpdate,
            Er.AssemblyImage newImage)
        {
            Er.AssemblyImage oldImage = Er.AssemblyImage.Load(fileReference.AssemblyInRegistryToUpdate.Id, this.registryConn);

            // Get the activities from the packages which refers this image.
            foreach (Er.AssemblyPackage package in oldImage.AssemblyPackages)
            {
                foreach (Er.Activity referredActivity in package.Activitys)
                {
                    // Get only the latest.
                    if (referredActivity.IsLatestVersion())
                    {
                        Guid activityId = (referredActivity as Er.IObject).ID;
                        if (!activitiesToUpdate.ContainsKey(activityId))
                        {
                            // Create the activity details. These activities will be updated once the activity import is done.
                            ActivityUpdateDetails activityUpdateDetails = new ActivityUpdateDetails() { Activity = referredActivity };
                            activityUpdateDetails.AssemblyImageToUpdate.Add(newImage);
                            activitiesToUpdate[activityId] = activityUpdateDetails;
                            activityUpdateDetails.packageId = (package as Er.IObject).ID;
                        }
                        else
                        {
                            ActivityUpdateDetails activityUpdateDetails = activitiesToUpdate[activityId];
                            activityUpdateDetails.AssemblyImageToUpdate.Add(newImage);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Create the newer versions of the activities which have been referenced by the DLLs which have meen marked for update.
        /// </summary>
        /// <param name="activitiesToUpdate">The activities to update.</param>
        private void CreateActivitiesVersionsWithNewImages(Dictionary<Guid, ActivityUpdateDetails> activitiesToUpdate)
        {
            try
            {
                Dictionary<Guid, Er.AssemblyPackage> packageMap = new Dictionary<Guid, Er.AssemblyPackage>();
                foreach (ActivityUpdateDetails activity in activitiesToUpdate.Values)
                {
                    Er.AssemblyPackage newPackage = null;
                    if (!packageMap.ContainsKey(activity.packageId))
                    {
                        activity.Activity.AssemblyPackages.GetEnumerator();
                        if (activity.Activity.AssemblyPackages.Count > 0)
                        {
                            Er.AssemblyPackage oldPackage = activity.Activity.AssemblyPackages[0];

                            // Create a package.
                            newPackage = Er.AssemblyPackage.Create(oldPackage.Name, this.registryConn);
                            newPackage.Save();

                            // Use the old images. Replace only the ones which have been updated.
                            foreach (Er.AssemblyImage image in oldPackage.AssemblyImages)
                            {
                                bool existsInList = activity.AssemblyImageToUpdate.Any(i => i.Filename.Equals(image.Filename));
                                if (!existsInList)
                                {
                                    newPackage.AssemblyImages.Add(image);
                                }
                            }

                            // Assign the images which have been updated.
                            foreach (Er.AssemblyImage newImage in activity.AssemblyImageToUpdate)
                            {
                                newPackage.AssemblyImages.Add(newImage);
                            }
                            packageMap[activity.packageId] = newPackage;
                        }
                    }
                    else
                    {
                        newPackage = packageMap[activity.packageId];
                    }
                    if (newPackage != null)
                    {
                        // Create new versions of the activities.
                        this.CreateNewVersion(activity.Activity, newPackage);
                    }
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                          ex,
                          TridentErrorConstants.ErrorNumber4000084,
                          TridentResourceManager.GetString("ErrorInCreatingActivityNewVersion"));
            }
        }

        /// <summary>
        /// Add a timestamp to the label.
        /// </summary>
        /// <param name="activity">Activity to which the timestamp is to be appended.</param>
        private static void AddTimestampToLabel(Er.Activity activity)
        {
            if (!string.IsNullOrEmpty(activity.Label))
            {
                activity.Label = string.Format(CultureInfo.InvariantCulture, "{0} {1}", activity.Label, DateTime.Now.ToString(CultureInfo.CurrentCulture));
            }
            else
            {
                activity.Label = string.Format(CultureInfo.InvariantCulture, "{0} {1}", activity.Name, DateTime.Now.ToString(CultureInfo.CurrentCulture));
            }
            activity.Save();
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        private class ActivityUpdateDetails
        {
            /// <summary>
            /// The package ID to which the image belongs to.
            /// </summary>
            public Guid packageId { get; set; }

            /// <summary>
            /// 
            /// </summary>
            public Er.Activity Activity { get; set; }

            /// <summary>
            /// 
            /// </summary>
            public Collection<Er.AssemblyImage> AssemblyImageToUpdate = new Collection<Er.AssemblyImage>();
        }
    }
}
